/*******************************************************************

   IPCWindow.c
	
	Does open a simple window with some easy gadgets, does create a
	new process, is protected to launch not twice and does show all
	arguments even if they are given with a new command.
					
*********************************************************************/

#define PARENT
#include "/includes/Window.h"

typedef struct _PassingData
{
        ULONG a4;                 // to store a4 (module is a4 relative)
        struct Library *library;  // to store a pointer to dopus5.library 
        struct Library *module;   // to store a pointer to this module
        IPCData *ipc;             // to store our NEW handle
             
        struct Screen *screen;
}  PassingData;   

/********************************************************************/
// locale prototypes and variables

ULONG __asm __saveds New_Proc_Startup( register __a0 IPCData *ipc,
                                       register __a1 PassingData *pd );
                                                                                                        
void __saveds New_Proc( void ); 

BOOL OpenDOpusWin( WindowHandle *wh ); // the same old function

BOOL HandleWindow( WindowHandle *wh ); // the same old function


extern IPCData *proc_ipc;
// declared in modinit.c, because must be initialized to NULL on startup 

/********************************************************************/
// this is the same function like in DetachWindow.
// it is the first special function we need...

void OwnWindow( STRPTR args, struct Screen *screen )
{
	PassingData *pd;
        
   if( (pd = AllocMemH(mempool, sizeof(PassingData))) ) // allocate some memory
     {
		  pd->screen = screen;          // store the screen pointer
                
		  if( !proc_ipc ) // only if the process is not already running
		    {
				 // now some special stuff, but everything is needed here...
             pd->a4      = getreg( REG_A4 ); 
             pd->module  = (struct Library *) getreg( REG_A6 );
             pd->library = DOpusBase;
                  
             // now we are ready to call IPC_Launch()
             IPC_Launch( 0, 
                         &proc_ipc,         // pointer to pointer to the IPC of the new process, for storing...
                         "ExampleWindow",  // name of the new process
                         (ULONG) New_Proc, // entrypoint of the new process
                         4096,             // stack to use
                         (ULONG) pd,       // data to pass to the new process
                         DOSBase );        // pointer to dos.library
								 
				 
                                                  
             if( !proc_ipc )              // if detaching failed...
				   {
						FreeMemH( pd );
				      return;
					}
					
				 Delay( 10 ); // give a small time for startup...
				              // not really needed
			 }
			 
		  // now should our process running
		  // since we use in the process not the arguments on startup to save
		  // some work, we have to pass it now.
		  
		  IPC_Command( proc_ipc,  // "address" (IPCData) of receiver
		               NULL,      // we use no commands here
							NULL,      // also no flags
							args,      // our data to pass to the new process
							NULL,      // no other data (will be FreeVec'd)
							REPLY_NO_PORT ); // use normal DOpus IPC_Reply() later
							
	     FreeMemH( pd );
	  }
		  // ready... :)
}

// let's do now the second special function

ULONG __asm __saveds New_Proc_Startup( register __a0 IPCData *ipc,
                                       register __a1 PassingData *pd )
{
        // you may use this function also to setup things for your
        // main process, but you should not call any IPC functions here !
        // we do only the minimum required..., but you will get some small
        // warnings from your compiler. Just ignore them now - they does
        // not appear, if we would do here some more things... 
        
        struct Library *DOpusBase; 

        // fix A4
        putreg( REG_A4, pd->a4 );

        // store IPC pointer
        pd->ipc = ipc;

        // get dopus.library - one warning now
        DOpusBase = pd->library;

        // now may follow your initialization
        
        // if something fails and you must quit, you should do:
        // return FALSE;

        // increase our library counter, so we can not be flushed
        // do not forget to decrease it, if your detached process ends 
        pd->module->lib_OpenCnt++;
        
        return TRUE; // all was successfully
} 

void __saveds New_Proc( void )
{
        // this is now just the same like until now our OwnWindow() function
        
        WindowHandle          *wh;
        PassingData           *pd;
		  IPCData               *ipc;
		  IPCMessage            *ipcmsg;
        struct Library        *DOpusBase;
		  struct Library        *module;
        
        // but we must do some additional things 
        
        // get dopus library
        if( !(DOpusBase = (struct Library *) FindName(&((struct ExecBase *)*((ULONG *)4))->LibList, "dopus5.library")) )
                return;
        
        // do startup 
        ipc = IPC_ProcStartup( (ULONG *) &pd, New_Proc_Startup );

        // fix A4 so we can access global data in the module (eg library bases)
        putreg( REG_A4, pd->a4 );
        
		  // we must store this pointer too 
		  module = pd->module;
		  
        // something failed until now ?
        if( !ipc )
          {
				 if( pd )
               {
						IPC_Free( pd->ipc ); // possible it has a value here 
                  FreeMemH( pd );      // free our memory
               }
                          
             return;
          }
                
        if( (wh = AllocMemH(mempool, sizeof(WindowHandle))) ) // allocate some memory
          {
             if( OpenDOpusWin(wh) )   // open the window
               {
						// before we have set on this place the value of our
						// textgadget, but now we have not the arguments. So
						// we wait to set the value until the command arrives. 
						
						while( TRUE ) 
                    {
							  // I use here Wait(), so it is easier with the changes
                                 
                       wh->signals = Wait( 1 << proc_ipc->command_port->mp_SigBit | // wait for IPC messages
							                      1 << wh->win->UserPort->mp_SigBit );   // wait for window events
                                                                                                
                       if( wh->signals & 1 << wh->win->UserPort->mp_SigBit )
                            if( HandleWindow(wh) )
                                 break;           // does end the while loop
							  
							  if( wh->signals & 1 << proc_ipc->command_port->mp_SigBit ) // if we have got an IPC message
							    {
									 while( (ipcmsg = (IPCMessage *) GetMsg(proc_ipc->command_port)) )
									   {
											
											// we copy now the arguments into the text gadget
                                 // if we have supplied some..., else it will be cleared
											// I do not cut here the last signs...
                                 
                                 SetGadgetValue( wh->olist, GADGET_ID_TEXT, (ULONG) ipcmsg->data );
											
											IPC_Reply( ipcmsg ); // do not use ReplyMsg() or something else !
										}
                         }                
                    }
						  
                  CloseConfigWindow( wh->win ); 
                }
                         
              FreeMemH( wh ); // free our memory
          }
			 
		  // decrease our Library access counter, since we have increased it before
        --module->lib_OpenCnt;   
        		  		  
        // since we are here a detached process, we must do some other cleanup too
        IPC_Free( proc_ipc );
		  
		  proc_ipc = NULL;    // do not forget this...                                                     
} 

/********************************************************************/
// This function does open our window. We could have done this in the
// function OwnWindow() too, but we need this function later again.

BOOL OpenDOpusWin( WindowHandle *wh )
{
	NewConfigWindow ncfgwin;     // we need a NewConfigWindow structure too
	                             // of couse you could also allocate it with
										  // AllocMemH()...
	
	// and have to fill it
	
	ncfgwin.nw_Parent = wh->screen;  // open on this screen
	
	// getting a localized title...
	ncfgwin.nw_Title  = DOpusGetString( locale, MSG_WINDOW_TITLE );
	
	ncfgwin.nw_Dims   = &cfgwin; // a pointer to the ConfigWin structure
	ncfgwin.nw_Locale = locale;  // the module locale pointer (from modinit.c)
	ncfgwin.nw_Port   = NULL;    // we doesn't supply a port
	ncfgwin.nw_Font   = NULL;    // just taking the screen font
	ncfgwin.nw_Flags  = WINDOW_REQ_FILL      | // fill with stripple pattern
	                    WINDOW_AUTO_KEYS     | // handle keys automatic
							  WINDOW_SCREEN_PARENT;  // nw_Parent points to a screen
	
	if( (wh->win = OpenConfigWindow(&ncfgwin)) )   // open the window
	  {
		  if( (wh->olist = AddObjectList(wh->win, odef)) ) // add the gadgets
		     	 return TRUE;
					
		  CloseConfigWindow( wh->win );	//	in error case do not forget :-)
	  }
	
	return FALSE;
}


/********************************************************************/
// we does only close the window, if the closegadget was pressed
// if you want to close it within a gadget, you must only in the
// right case set "stop" to TRUE

BOOL HandleWindow( WindowHandle *wh )
{
	 BOOL stop = FALSE;
	 ULONG value;
	 
	 while( !stop && (wh->imsg = GetWindowMsg(wh->win->UserPort)) )
		{
			switch( wh->imsg->Class )  // let's handle the IDCMP
			  {
				  case IDCMP_GADGETUP:
				                          switch( GET_ID(wh->imsg) )
	                                     {
														 case GADGET_ID_CYCLE:  // we copy simply the same text to the text gadget
			
			                                                         value = GetGadgetValue( wh->olist, GADGET_ID_CYCLE ) + MSG_CLICK_ME;
										                                    SetGadgetValue( wh->olist, GADGET_ID_TEXT, (ULONG) DOpusGetString(locale, value) );
										                                    break;
			
			                                  case GADGET_ID_OKAY:   // doing a message
			                                                         
																						SetGadgetValue( wh->olist, GADGET_ID_TEXT, (ULONG) DOpusGetString(locale, MSG_OKAY_DONE) );
										                                    break;
										 			
			                                  case GADGET_ID_CANCEL: 
			                                                         SetGadgetValue( wh->olist, GADGET_ID_TEXT, (ULONG) DOpusGetString(locale, MSG_CANCEL_DONE) );
										                                    break;
		                                  }
																 
												  break;
									 
				  case IDCMP_CLOSEWINDOW:
				                          // we can not simply return here, the IntuiMessage must replied first
												  
									           stop = TRUE;
												  break;									 
			  }
								 
			ReplyWindowMsg( wh->imsg );  
							  
			// remember: You should not use any other routines
			// to get/reply the messages of this window than
			// GetWindowMsg() and ReplyWindowMsg() !!
	   }
						  	 
    return stop;
}